using System;
using System.Reflection;
using Agatha.Common.InversionOfControl;
using Agatha.Common.WCF;

namespace Agatha.Common
{
  
	public class ClientConfiguration
	{
		private readonly Assembly requestsAndResponsesAssembly;
		private readonly IContainer container;

		public Type RequestDispatcherImplementation { get; set; }
		public Type RequestDispatcherFactoryImplementation { get; set; }
		public Type RequestProcessorImplementation { get; set; }
		public Type AsyncRequestDispatcherImplementation { get; set; }
		public Type AsyncRequestDispatcherFactoryImplementation { get; set; }
		public Type AsyncRequestProcessorImplementation { get; set; }
		public Type ContainerImplementation { get; private set; }

		public ClientConfiguration(Assembly requestsAndResponsesAssembly, IContainer container)
		{
			this.requestsAndResponsesAssembly = requestsAndResponsesAssembly;
			this.container = container;
			SetDefaultImplementations();
		}

		public ClientConfiguration(Assembly requestsAndResponsesAssembly, Type containerImplementation)
		{
			this.requestsAndResponsesAssembly = requestsAndResponsesAssembly;
			ContainerImplementation = containerImplementation;
			SetDefaultImplementations();
		}

		private void SetDefaultImplementations()
		{
			RequestDispatcherImplementation = typeof(RequestDispatcher);
			RequestDispatcherFactoryImplementation = typeof(RequestDispatcherFactory);
			RequestProcessorImplementation = typeof(RequestProcessorProxy);
			AsyncRequestDispatcherImplementation = typeof(AsyncRequestDispatcher);
			AsyncRequestDispatcherFactoryImplementation = typeof(AsyncRequestDispatcherFactory);
			AsyncRequestProcessorImplementation = typeof(AsyncRequestProcessorProxy);
		}

		public void Initialize()
		{
			if (IoC.Container == null)
			{
				IoC.Container = container ?? (IContainer)Activator.CreateInstance(ContainerImplementation);
			}

			IoC.Container.Register(typeof(IRequestProcessor), RequestProcessorImplementation, Lifestyle.Transient);
			IoC.Container.Register(typeof(IRequestDispatcher), RequestDispatcherImplementation, Lifestyle.Transient);
			IoC.Container.Register(typeof(IRequestDispatcherFactory), RequestDispatcherFactoryImplementation, Lifestyle.Singleton);
			IoC.Container.Register(typeof(IAsyncRequestProcessor), AsyncRequestProcessorImplementation, Lifestyle.Transient);
			IoC.Container.Register(typeof(IAsyncRequestDispatcher), AsyncRequestDispatcherImplementation, Lifestyle.Transient);
			IoC.Container.Register(typeof(IAsyncRequestDispatcherFactory), AsyncRequestDispatcherFactoryImplementation, Lifestyle.Singleton);
			RegisterRequestAndResponseTypes();
		}

		private void RegisterRequestAndResponseTypes()
		{
			KnownTypeProvider.RegisterDerivedTypesOf<Request>(requestsAndResponsesAssembly);
			KnownTypeProvider.RegisterDerivedTypesOf<Response>(requestsAndResponsesAssembly);
		}
	}
}